import pandas as pd
from openai import OpenAI
import re
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from threading import Thread
import json
import os

class MedicalReportChecker:
    def __init__(self):
        self.window = tk.Tk()
        self.window.title("医学报告质控系统")
        self.window.geometry("800x600")
        
        # 尝试加载保存的API密钥
        self.config_file = 'config.json'
        self.api_key = self.load_api_key()
        
        self.create_widgets()
        
    def load_api_key(self):
        """从配置文件加载API密钥"""
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r') as f:
                    config = json.load(f)
                    return config.get('api_key', '')
        except:
            return ''
        return ''
    
    def save_api_key(self):
        """保存API密钥到配置文件"""
        config = {'api_key': self.api_key_entry.get()}
        with open(self.config_file, 'w') as f:
            json.dump(config, f)
    
    def create_widgets(self):
        # API密钥输入框
        api_frame = ttk.LabelFrame(self.window, text="API设置", padding="10")
        api_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Label(api_frame, text="API密钥:").pack(side="left")
        self.api_key_entry = ttk.Entry(api_frame, width=50)
        self.api_key_entry.pack(side="left", padx=5)
        self.api_key_entry.insert(0, self.api_key)
        
        ttk.Button(api_frame, text="保存API密钥", command=self.save_api_key).pack(side="left", padx=5)
        
        # 文件选择框
        file_frame = ttk.LabelFrame(self.window, text="文件选择", padding="10")
        file_frame.pack(fill="x", padx=10, pady=5)
        
        # 输入文件选择
        input_frame = ttk.Frame(file_frame)
        input_frame.pack(fill="x", pady=5)
        
        ttk.Label(input_frame, text="输入文件:").pack(side="left")
        self.file_path_var = tk.StringVar()
        self.file_path_entry = ttk.Entry(input_frame, textvariable=self.file_path_var, width=50)
        self.file_path_entry.pack(side="left", padx=5)
        
        ttk.Button(input_frame, text="选择文件", command=self.select_input_file).pack(side="left", padx=5)
        
        # 输出目录选择
        output_frame = ttk.Frame(file_frame)
        output_frame.pack(fill="x", pady=5)
        
        ttk.Label(output_frame, text="输出目录:").pack(side="left")
        self.output_dir_var = tk.StringVar()
        self.output_dir_entry = ttk.Entry(output_frame, textvariable=self.output_dir_var, width=50)
        self.output_dir_entry.pack(side="left", padx=5)
        
        ttk.Button(output_frame, text="选择目录", command=self.select_output_dir).pack(side="left", padx=5)
        
        # 进度显示
        progress_frame = ttk.LabelFrame(self.window, text="处理进度", padding="10")
        progress_frame.pack(fill="x", padx=10, pady=5)
        
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(progress_frame, variable=self.progress_var, maximum=100)
        self.progress_bar.pack(fill="x", padx=5, pady=5)
        
        # 日志显示
        log_frame = ttk.LabelFrame(self.window, text="处理日志", padding="10")
        log_frame.pack(fill="both", expand=True, padx=10, pady=5)
        
        self.log_text = tk.Text(log_frame, height=10)
        self.log_text.pack(fill="both", expand=True)
        
        # 控制按钮
        button_frame = ttk.Frame(self.window)
        button_frame.pack(fill="x", padx=10, pady=5)
        
        ttk.Button(button_frame, text="开始处理", command=self.start_processing).pack(side="left", padx=5)
        ttk.Button(button_frame, text="退出", command=self.window.quit).pack(side="right", padx=5)
    
    def select_input_file(self):
        """选择输入文件"""
        filename = filedialog.askopenfilename(
            title="选择Excel文件",
            filetypes=[("Excel文件", "*.xlsx *.xls")]
        )
        if filename:
            self.file_path_var.set(filename)
            # 默认将输出目录设置为输入文件所在目录
            self.output_dir_var.set(os.path.dirname(filename))
    
    def select_output_dir(self):
        """选择输出目录"""
        dirname = filedialog.askdirectory(
            title="选择输出目录"
        )
        if dirname:
            self.output_dir_var.set(dirname)
    
    def log_message(self, message):
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)
    
    def check_gender_specific_terms(self, gender, description):
        """检查性别相关的不当描述"""
        male_organs = ['前列腺', '睾丸', '阴茎', '精囊']
        female_organs = ['子宫', '卵巢', '输卵管', '阴道', '附件']
        
        if gender == '女':
            found_terms = [term for term in male_organs if term in description]
            if found_terms:
                return f"错误：女性报告中出现男性器官描述：{', '.join(found_terms)}"
        elif gender == '男':
            found_terms = [term for term in female_organs if term in description]
            if found_terms:
                return f"错误：男性报告中出现女性器官描述：{', '.join(found_terms)}"
        return ""
    
    def check_spelling(self, text):
        """使用API检查文本中的错别字"""
        try:
            client = OpenAI(
                api_key=self.api_key_entry.get(),
                base_url="https://api.deepseek.com"
            )
            response = client.chat.completions.create(
                model="deepseek-chat",
                messages=[
                    {"role": "system", "content": "您是一位拥有30年临床经验的医学影像诊断权威专家，以严谨治学著称。请以专业审校标准对下列医学影像报告进行全方位文字核查。若发现错误，请以'【错误定位】错误词汇 → 正确形式'格式分项列出；如果没有，请一定要只回复'无错别字'。"},
                    {"role": "user", "content": text}
                ],
                stream=False
            )
            return response.choices[0].message.content
        except Exception as e:
            return f"API调用错误：{str(e)}"
    
    def process_file(self):
        try:
            file_path = self.file_path_var.get()
            output_dir = self.output_dir_var.get()
            
            if not file_path:
                messagebox.showerror("错误", "请选择Excel文件")
                return
            
            if not output_dir:
                messagebox.showerror("错误", "请选择输出目录")
                return
            
            if not os.path.exists(output_dir):
                messagebox.showerror("错误", "输出目录不存在")
                return
            
            self.log_message("开始处理文件...")
            df = pd.read_excel(file_path)
            
            required_columns = ['性别', '影像学表现', '诊断结果']
            if not all(col in df.columns for col in required_columns):
                self.log_message("错误：Excel文件缺少必要的列")
                return
            
            # 创建输出文件名（在指定目录下）
            input_filename = os.path.basename(file_path)
            output_filename = os.path.splitext(input_filename)[0] + '_checked.xlsx'
            output_file = os.path.join(output_dir, output_filename)
            
            # 如果输出文件已存在，先读取已有的结果
            if os.path.exists(output_file):
                try:
                    existing_df = pd.read_excel(output_file)
                    # 如果已有结果文件包含质控结果列，则使用已有结果
                    if '质控结果' in existing_df.columns:
                        df['质控结果'] = existing_df['质控结果']
                    else:
                        df['质控结果'] = ''
                except:
                    df['质控结果'] = ''
            else:
                df['质控结果'] = ''
            
            total_rows = len(df)
            
            for index, row in df.iterrows():
                try:
                    self.progress_var.set((index + 1) / total_rows * 100)
                    self.log_message(f"正在处理第 {index + 1}/{total_rows} 条记录...")
                    
                    # 如果该行已经有处理结果，则跳过
                    if pd.notna(df.at[index, '质控结果']) and df.at[index, '质控结果'] != '':
                        self.log_message(f"第 {index + 1} 行已处理，跳过")
                        continue
                    
                    # 检查是否存在空值
                    if pd.isna(row['性别']) or pd.isna(row['影像学表现']) or pd.isna(row['诊断结果']):
                        df.at[index, '质控结果'] = '数据不完整，跳过检查'
                        self.log_message(f"第 {index + 1} 行数据不完整，已跳过")
                    else:
                        # 确保所有值都是字符串类型
                        try:
                            gender = str(row['性别']).strip()
                            imaging = str(row['影像学表现']).strip()
                            diagnosis = str(row['诊断结果']).strip()
                        except:
                            df.at[index, '质控结果'] = '数据格式错误，跳过检查'
                            self.log_message(f"第 {index + 1} 行数据格式错误，已跳过")
                            continue
                        
                        # 检查性别值是否有效
                        if gender not in ['男', '女']:
                            df.at[index, '质控结果'] = '性别值无效，跳过检查'
                            self.log_message(f"第 {index + 1} 行性别值无效，已跳过")
                        else:
                            results = []
                            
                            # 只有当影像学表现不为空时才进行性别相关检查
                            if imaging:
                                gender_check = self.check_gender_specific_terms(gender, imaging)
                                if gender_check:
                                    results.append(gender_check)
                                
                                spelling_check_imaging = self.check_spelling(imaging)
                                if spelling_check_imaging != '无错别字':
                                    results.append(f"影像学表现：{spelling_check_imaging}")
                            
                            # 只有当诊断结果不为空时才进行检查
                            if diagnosis:
                                spelling_check_diagnosis = self.check_spelling(diagnosis)
                                if spelling_check_diagnosis != '无错别字':
                                    results.append(f"诊断结果：{spelling_check_diagnosis}")
                            
                            df.at[index, '质控结果'] = ' | '.join(results) if results else '通过'
                    
                    # 每处理完一行就保存一次结果
                    df.to_excel(output_file, index=False)
                    self.window.update()
                    
                except Exception as e:
                    error_msg = f"处理第 {index + 1} 行时出错：{str(e)}"
                    self.log_message(error_msg)
                    df.at[index, '质控结果'] = f"处理出错：{str(e)}"
                    df.to_excel(output_file, index=False)
                    continue
            
            self.log_message(f"处理完成！结果已保存至：{output_file}")
            messagebox.showinfo("完成", "文件处理完成！")
            
        except Exception as e:
            self.log_message(f"处理过程中出现错误：{str(e)}")
            messagebox.showerror("错误", f"处理过程中出现错误：{str(e)}")
        
        finally:
            self.progress_var.set(0)
    
    def start_processing(self):
        if not self.api_key_entry.get():
            messagebox.showerror("错误", "请输入API密钥")
            return
        
        # 在新线程中处理文件，避免界面卡死
        Thread(target=self.process_file, daemon=True).start()
    
    def run(self):
        self.window.mainloop()

if __name__ == "__main__":
    app = MedicalReportChecker()
    app.run() 
